package com.zyjc.city.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.zyjc.city.model.ApiResult;
import com.zyjc.city.model.dto.AreaPersonDto;
import com.zyjc.city.model.dto.TokenDto;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author ckj
 * @date 2024年04月01日 14:23
 */
@Slf4j
public class CqcHttpUtil {
    private final static String BASE_URL = "http://172.18.39.22:8081";
    private final static String CHARSET = "UTF-8";
    private final static int BUFFER_SIZE = 4096;
    private final static String CHANNEL_CODE = "DD";
    private final static String DES_KEY = "DD";


    /***
     * 入口
     * @param args
     */
    public static void main(String[] args) {
        //渠道编码
        String channelCode = "1";
        //密钥
        String desKey = "12345678";
//        getToken(channelCode,desKey);




        String result = "{\"code\":\"0\",\"data\":[{\"date_time\":\"2021-08-10 11:20:10\",\"cnt_resi\":12450,\"cnt\":89875}],\"description\":\"\",\"success\":true}";
        ApiResult<List<AreaPersonDto>> apiResult = JSON.parseObject(result, new TypeReference<ApiResult<List<AreaPersonDto>>>(){});
        log.info("{}获取token", LocalDate.now());
    }

    /***
     * 获取token
     * @param channelCode
     * @param desKey
     */
    public static void getToken(String channelCode, String desKey) {
        try {
            String url = BASE_URL + "/openplat-sys-core/api/interface/sys/channelinterface/createtoken?channelCode=" + channelCode;
            String msg = "{}";
            String result = callInterface(url, msg, desKey);
            ApiResult<TokenDto> apiResult = JSON.parseObject(result, new TypeReference<ApiResult<TokenDto>>() {
            });
            log.info("{}获取token,{}", LocalDateTime.now(), apiResult.getData().getTokenCode());
            CaffeineUtil.put("token", apiResult.getData().getTokenCode());
        } catch (Exception ex) {
            log.error("{}获取token失败", LocalDateTime.now());
        }
    }

    public static void getToken() {
        getToken(CHANNEL_CODE, DES_KEY);
    }

    public static String callInterface(String url, String msg) throws Exception {
        String urlS = BASE_URL + url;
        return callInterface(urlS, msg,DES_KEY);
    }


    /***
     * 调用接口，并处理加解密
     * @param url
     * @param msg
     * @param desKey
     * @throws Exception
     */
    private static String callInterface(String url, String msg, String desKey) throws Exception {
        if (msg == null) {
            msg = "";
        }
        //参数加密
        byte[] paraBytes = encryptDES(msg.getBytes(CHARSET), desKey);
        //调用HTTP接口
        byte[] resultEncodeBytes = callStreamByte("POST", url, paraBytes);
        //返回结果解密
        byte[] resultBytes = decryptDES(resultEncodeBytes, desKey);
        //返回结果构造成字符串
        String result = new String(resultBytes, CHARSET);
        return result;
    }

    /***
     * 流方式提交
     * @requestMehtod 设置请求类型，可以为POST、PUT
     * @param pathUrl
     * @param msg
     * @return
     * @throws Exception
     */
    public static byte[] callStreamByte(String requestMehtod, String pathUrl, byte[] requestStringBytes) throws Exception {
        HttpURLConnection httpConn = null;
        try {
            URL url = new URL(pathUrl);
            httpConn = (HttpURLConnection) url.openConnection();

            // //设置连接属性
            httpConn.setDoOutput(true);// 使用 URL 连接进行输出
            httpConn.setDoInput(true);// 使用 URL 连接进行输入
            httpConn.setUseCaches(false);// 忽略缓存
            httpConn.setRequestMethod("POST");// 设置URL请求方法


            //报文长度
            int len = 0;
            if (requestStringBytes != null) {
                len = requestStringBytes.length;
            }
            httpConn.setRequestProperty("Content-length", "" + len);
            httpConn.setRequestProperty("Charset", CHARSET);
            httpConn.setRequestProperty("Content-Type", "application/octet-stream");


            // 建立输出流，并写入数据
            OutputStream outputStream = httpConn.getOutputStream();
            if (requestStringBytes != null) {
                outputStream.write(requestStringBytes);
            }
            outputStream.close();
            // 获得响应状态
            int responseCode = httpConn.getResponseCode();
            //StringBuffer sb = new StringBuffer();
            byte[] result = null;
            if (HttpURLConnection.HTTP_OK == responseCode || HttpURLConnection.HTTP_NO_CONTENT == responseCode) {// 连接成功

                InputStream in = httpConn.getInputStream();

                result = converStreamToBytes(in);
                in.close();
            } else {
                System.out.println("返回HTTP状态:" + responseCode);
                if (responseCode >= 400) {
                    throw new Exception("HTTP返回错误状态:[" + responseCode + "]");
                }
            }
            return result;
        } catch (Exception e) {
            System.out.println("访问[" + pathUrl + "]" + e);
            throw e;
        } finally {
            if (httpConn != null) {
                httpConn.disconnect();
            }
        }
    }

    /***
     * 获取返回的字节数组
     *
     * @return
     * @throws Exception
     */
    public static byte[] converStreamToBytes(InputStream in) throws Exception {
        byte[] result = null;
        try {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            byte[] data = new byte[BUFFER_SIZE];
            int count = -1;
            while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
                outStream.write(data, 0, count);

            data = null;
            result = outStream.toByteArray();
            outStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /***
     * DES加密,DES对称属于对称加密
     *   待加密码字符串
     * @param desKey DES密钥,长度必须8的倍数
     * @return
     * @throws Exception
     */
    public static byte[] encryptDES(byte[] bytes, String desKey) throws Exception {
        try {
            if (bytes == null) {
                return null;
            }
            SecureRandom sr = new SecureRandom();
            DESKeySpec dks = new DESKeySpec(desKey.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr);
            byte[] result = cipher.doFinal(bytes);
            return result;
        } catch (Exception ex) {
            System.out.println("DES加密失败," + ex);
            throw ex;
        }
    }

    /***
     * DES解密
     * @param bytes
     * @param desKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptDES(byte[] bytes, String desKey) throws Exception {
        try {
            if (bytes == null) {
                return null;
            }
            SecureRandom sr = new SecureRandom();
            DESKeySpec dks = new DESKeySpec(desKey.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, sr);
            return cipher.doFinal(bytes);
        } catch (Exception ex) {
            System.out.println("DES解密失败," + ex);
            throw ex;
        }
    }
}
